﻿#region License Info
//Component of Cronos Package, http://www.codeplex.com/cronos
//Copyright (C) 2009 Anthony Brockwell

//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either version 2
//of the License, or (at your option) any later version.

//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.

//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#endregion


using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using ABMath.ModelFramework.Data;
using ABMath.ModelFramework.Models;

namespace ExtraControlLibrary.Forms
{
    public partial class LinkSocketChooser : Form
    {
        public struct IntPair
        {
            public int source;
            public int sink;
        }

        public int SourceIndex { get; set; }
        public int SinkIndex { get; set; }

        private IList<List<Type>> sourceType;
        private IList<List<Type>> sinkTypes;
        private IList<string> sources;
        private IList<string> sinks;

        private List<IntPair> possibilities;

        public int NumPossibilities { get { return possibilities.Count; } }
        public IntPair FirstPossibility { get { return possibilities[0]; } }

        /// <summary>
        /// this function works out all possible source/sink matches in terms of types
        /// </summary>
        private void BuildPossibilities()
        {
            for (int i=0 ; i<sources.Count ; ++i)
                for (int j = 0; j < sinks.Count; ++j)
                {
                    bool oneMatch = false;
                    foreach (var st in sourceType[i])
                      if (ListContains(sinkTypes[j], st))
                        oneMatch = true;
                    if (oneMatch)
                        possibilities.Add(new IntPair() {source = i, sink = j});
                }
        }

        private static bool ListContains(IEnumerable<Type> list, Type t)
        {
            bool hasit = false;
            if (list == null)
                return false;
            foreach (var l in list)
                if (l==t)
                    hasit = true;
            return hasit;
        }

        public LinkSocketChooser(IList<string> sources, IList<List<Type>> sourceType,
            IList<string> sinks, IList<List<Type>> sinkTypes)
        {
            InitializeComponent();

            possibilities = new List<IntPair>();

            this.sourceType = sourceType;
            this.sinkTypes = sinkTypes;
            this.sources = sources;
            this.sinks = sinks;

            for (int si = 0 ; si < sources.Count ; ++si)
            {
                var x = sources[si];
                var lvi = new ListViewItem(x, 0);
                lvi.SubItems.Add(ListContains(sourceType[si], typeof(TimeSeries)) ? "+" : "-");
                lvi.SubItems.Add(ListContains(sourceType[si], typeof(MVTimeSeries)) ? "+" : "-");
                lvi.SubItems.Add(ListContains(sourceType[si], typeof(Model)) ? "+" : "-");
                listViewOutputs.Items.Add(lvi);
            }

            for (int si = 0; si < sinks.Count; ++si )
            {
                var x = sinks[si];
                var lvi = new ListViewItem(x, 0);
                lvi.SubItems.Add(ListContains(sinkTypes[si], typeof(TimeSeries)) ? "+" : "-");
                lvi.SubItems.Add(ListContains(sinkTypes[si], typeof(MVTimeSeries)) ? "+" : "-");
                lvi.SubItems.Add(ListContains(sinkTypes[si], typeof(Model)) ? "+" : "-");
                listViewInputs.Items.Add(lvi);
            }

            SourceIndex = 0;
            SinkIndex = 0;

            BuildPossibilities();

            if (NumPossibilities > 0)
            {
                listViewInputs.Items[possibilities[0].sink].Selected = true;
                listViewOutputs.Items[possibilities[0].source].Selected = true;
            }
        }

        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        {
            SourceIndex = listViewOutputs.SelectedIndices[0];
            SinkIndex = listViewInputs.SelectedIndices[0];
            base.OnClosing(e);
        }

        private void LinkSocketChooser_FormClosing(object sender, FormClosingEventArgs e)
        {
            // check type compatibility
            bool gotMatch = false;
            foreach (var st in sourceType[SourceIndex])
                if (ListContains(sinkTypes[SinkIndex], st))
                    gotMatch = true;
            if (!gotMatch)
            {

                MessageBox.Show("Output type must be one of the allowed types for the specified input.", "Error");
                e.Cancel = true;
            }
        }
    }
}
